home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / UTIL / Alpha 6.5.sit / Tcl / Modes / perl.tcl < prev    next >
Text File  |  1996-08-15  |  47KB  |  1,614 lines

  1. #############################################################################
  2. # MacPerl.tcl
  3. # -----------
  4. #
  5. # This is a set of routines that allow Alpha to act as a front end for the
  6. # standalone MacPerl application and that allow Perl scripts to be used as 
  7. # text filters in Alpha.  These functions are accessed through a special 
  8. # MacPerl menu.
  9. #
  10. # The features of this package are explained in the file "MacPerl Help",
  11. # accessible from the Help menu.
  12. #
  13. #############################################################################
  14. #
  15. # If you don't already have MacPerl, it's available by anonymous ftp from
  16. # the umich site
  17. #
  18. #   mac.archive.umich.edu    [141.211.165.34]    mac/development/languages
  19. #
  20. # and its mirrors.  Also, MacPerl's home site is 
  21. #
  22. #   ftp.switch.ch            [130.59.1.40]        software/mac/src/mpw_c
  23. #
  24. # MacPerl was written (ported to the Mac) by 
  25. #        Matthias Neeracher <neeri@iis.ee.ethz.ch> , and
  26. #        Tim Endres <time@ice.com>.
  27. #
  28. #############################################################################
  29. # Author: W. Thomas Pollard <pollard@chem.columbia.edu>
  30. #
  31. # Version History:
  32. #
  33. # 2.51 1/96  -  Fixed problem w/ "Tell MacPerl:Save As..."
  34. # 2.5  1/96  -  Colorization and cmd-dbl-click modified to support Perl 5 docs
  35. # 2.41 7/95  -  Minor tweaks
  36. # 2.4  7/95  -  Fixed bugs affecting running unsaved scripts and error handling
  37. # 2.3  7/95  -  Minor tweaks and code rearrangement.
  38. # 2.2  6/95  -  Text filters act only on current line if "Apply to Buffer" is
  39. #                  false and no text has been selected.
  40. #               Bug fix in error-marking for scripts sent as AppleEvent params.
  41. #               Cmd-dbl-clicking a function call jumps to function, if
  42. #                  defined in the same file.
  43. # 2.1  6/95  -  Cmd-dbl-clicking a 'require'd filename opens the file.
  44. # 2.0  6/95  -  Minor bug fixes (incl. keyword decapitalization)
  45. #               Alpha 6.0b17 compatibility updates.
  46. #               Text Filters folder is settable from the App Paths menu now.
  47. # 1.9  5/95  -  Cmd-dbl-clicking Perl keywords and special variables displays
  48. #                  the man page info.
  49. # 1.81 4/95  -  one very minor Alpha compatibility update (winInfo->getWinInfo).
  50. # 1.8  4/95  -  Menu reorganized somewhat.
  51. #               Text Filters folder can now be anywhere.
  52. #               "ApplyToBuffer" flag ignored if text has been selected.
  53. #               Bug fixes.
  54. # 1.7  1/95  -  Updated to take advantage of MacPerl 4.1.4 AppleEvent features:
  55. #                1) Text filters use 'batch' doScript (.: STDOUT file obsolete)
  56. #                2) Filter scripts sent as doScript params (.: SCRIPT file obsolete)
  57. #                3) "Save As Droplet" and "Save as Runtime" commands added.
  58. #               Errors generated in 'require'd files are now displayed correctly
  59. # 1.6 10/94  -  "UseDebugger" flag added (forces scripts to run under debugger).
  60. #               Key bindings added for some menu commands.
  61. #               "perlDoScript{,2,3}" procs consolidated into a single proc.
  62. #               "saveAndRun" option added.
  63. #               Command-line args now parsed into units more correctly, in
  64. #                   particular, quoted file names aren't broken up.
  65. #               "Close Output Window" added to "Tell MacPerl" menu.
  66. #               Updated for Alpha 5.98 to load when menu is inserted.
  67. #               The error messages window is now recycled.
  68. #               "perlRecycleOutput" recycles output window.
  69. #               Minor bug fixes.
  70. # 1.5  9/94  -  MacPerl menu rearranged somewhat.
  71. #               Explicit "Get Output Window" command added to menu.
  72. #               Reading "#!" line for args is incompatible w/ standard,
  73. #                   so it's been dropped.
  74. #               Only scan the first 40 output lines for error messages (faster)
  75. #                "wrapFilterScript" no longer opens STDIN
  76. #               Text filters may now use command-line args
  77. #               STDIN for text filters passed as explicit cmd-line arg 
  78. # 1.4  9/94  -  The "#!" line of every script is read for command-line args,
  79. #                    which are passed explicitly to MacPerl with the script.
  80. #                "PromptForArgs" menu flag added.
  81. #                "perlCmdlineArgs" modeVar holds default command-line args.
  82. #                Scripts are sent using custom "perlDoScript2" proc, which
  83. #                    allows passing of explicit command-line args.
  84. # 1.3  9/94  -  When any script generates a compilation error, the file 
  85. #                    containing the script is brought up with the offending 
  86. #                    line highlighted; all error output is also written to
  87. #                    a "Perl Error Messages" window.
  88. #                'repeatLastFilter' runs again the last text-filter script used.
  89. #                'perlLastFilter' modeVar holds pathname of last filter.
  90. #                Menu flags now mirrored as modeVars, so they can be saved and
  91. #                    restored between sessions.
  92. #                Minor bug fixes.
  93. # 1.2  8/94  -  'retrieveOutput' and 'autoSwitch' flags added.
  94. #                'openInMacperl' added.
  95. #                MacPerl output window now closed before new scripts are sent.
  96. #                Filters now abort if there are compilation errors, and
  97. #                MacPerl diagnostic output retrieved and displayed in Alpha.
  98. # 1.1  8/94  -  'quitMacperl' added.
  99. #               perl-mode file-marking updated for Alpha 5.90
  100. #               Simplified installation via 'loadMacperl'(Pete Keleher). 
  101. # 1.0  7/94  -  perl-mode setup updated for Alpha 5.85:
  102. #                    keyword colorization supported
  103. #                    custom file-marking added
  104. #               #! lines in filter scripts now handled correctly 
  105. #               Workarounds installed for AppleEvent bug in MacPerl 4.1.3
  106. # 0.9  3/94  -  perl-mode stuff added, and
  107. #               highlighted 'Perl commands' file (man page) prepared
  108. #               minor bug fixes, too
  109. # 0.8  3/94  -  flags are now check-marked
  110. # 0.7  3/94  -  nested Text Filters folder now supported
  111. #               menu format modified somewhat
  112. # 0.6  3/94  -  'applyToBuffer' flag added
  113. #               scripts in Alpha buffers can now be used as filters 
  114. # 0.5  2/94  -  'filters', 'open special' submenu added
  115. #               'overwrite' flag added
  116. # 0.2  1/94  -  menu support added (Martijn Koster <m.koster@nexor.co.uk>)
  117. #               'execute selection', 'execute buffer' commands added
  118. # 0.1  9/93  -  text filter functionality created
  119. #                  
  120. ##############################################################################
  121. #
  122. proc dummyPerl {} {
  123. }
  124.  
  125. #############################################################################
  126. #  Default settings for the Perl menu flags  
  127. #
  128. set perlDefault(perlUseDebug) 0
  129. set perlDefault(perlGetOutput) 1
  130. set perlDefault(perlAutoSwitch) 1
  131. set perlDefault(perlOverwrite) 0
  132. set perlDefault(perlUsebuffer) 1
  133. set perlDefault(perlPromptArgs) 0
  134. set perlDefault(perlRecycleOutput) 0
  135. set perlDefault(perlPrevScript) {*startup*}
  136. set perlDefault(perlCmdlineArgs) {}
  137. set perlDefault(perlVersion) {4}
  138.  
  139. if {![info exists perlFilterPath]} {
  140.     set perlFilterPath "$HOME:Tcl:UserCode:Text Filters:"
  141. }
  142.  
  143. ##NEW
  144. if {![info exists perlDocs]} {
  145.     set perlDocs "$HOME:Help:Perl Commands"
  146. }
  147. ##
  148.  
  149. foreach var [array names perlDefault] {
  150.     if (![info exists PerlmodeVars($var)]) { 
  151.         set $var $perlDefault($var) 
  152.     } else {
  153.         set $var $PerlmodeVars($var) 
  154.     }
  155. }
  156. unset perlDefault
  157.  
  158. ##############################################################################
  159. # Make duplicate copies of these variables as modeVars, taking responsibility
  160. # for keeping the two sets consistent (argh!)
  161. #
  162. # (Maybe it's OK now to let them _just_ be modeVars, and not also ordinary
  163. # variables?)
  164. #
  165.  
  166. newModeVar Perl perlUseDebug $perlUseDebug 1
  167. newModeVar Perl perlGetOutput $perlGetOutput 1
  168. newModeVar Perl perlAutoSwitch $perlAutoSwitch 1
  169. newModeVar Perl perlOverwrite $perlOverwrite 1
  170. newModeVar Perl perlUsebuffer $perlUsebuffer 1
  171. newModeVar Perl perlPromptArgs $perlPromptArgs 1
  172. newModeVar Perl perlRecycleOutput $perlRecycleOutput 1
  173.  
  174. newModeVar Perl perlLastFilter $perlPrevScript 0
  175. newModeVar Perl perlCmdlineArgs $perlCmdlineArgs 0
  176.  
  177. ##############################################################################
  178. # Other Perl-mode variable definitions
  179. #
  180. newModeVar Perl elecRBrace        {0} 1
  181. newModeVar Perl elecLBrace        {1} 1
  182. newModeVar Perl electricSemi    {0} 1
  183. newModeVar Perl electricTab        {1} 1
  184. newModeVar Perl electricReturn    {1} 1
  185. newModeVar Perl wordBreak        {(¥$)?¥w+} 0
  186. newModeVar Perl prefixString    {# } 0
  187. newModeVar Perl wordWrap        {0} 1
  188. newModeVar Perl funcExpr        {^sub *([+-a-zA-Z0-9]+)} 0
  189. newModeVar Perl wordBreakPreface        {[^a-zA-Z0-9_¥$]} 0
  190. newModeVar Perl autoMark    1    1
  191. newModeVar Perl stringColor    green    0
  192.  
  193. newModeVar Perl perlVersion $perlVersion 0
  194.  
  195. ##############################################################################
  196. # Miscellaneous definitions
  197. #
  198. set perlErrorWindow {* Perl Error Messages *}
  199. set perlOutputWindow {* Perl Output *}
  200.  
  201. set perlFilterMenu "textFilters"
  202.  
  203. set modeCode ":Tcl:Modes:perl${perlVersion}.tcl"
  204. if {[catch {source $HOME$modeCode}]} {
  205.     alertnote "Couldn't load the Perl-mode colorization file ¥"$modeCode¥".  Contact the maintainer."
  206. }
  207.  
  208. #############################################################################
  209. #  Return paths to standard files, based on the path to MacPerl:
  210. #
  211. proc macperlFolder {} {
  212.    set name [nameFromAppl McPL]
  213.    regexp {(.*):([^:]*)} $name pathname dirname filename
  214.    return ${dirname}:
  215. }
  216.  
  217. proc stdinPath {} {
  218.    return [macperlFolder]STDIN
  219. }
  220.  
  221. proc scriptPath {} {
  222.    return [macperlFolder]SCRIPT
  223. }
  224.  
  225. #############################################################################
  226. # Define the dummy proc that will be called when the perl menu
  227. # is first inserted into the menubar
  228. #
  229. proc perlMenu {} {}
  230.  
  231. #############################################################################
  232. #  Build the perl menu
  233. #            
  234. set perlMenu "・132"
  235. set perlOptsMenu "generalOptions"
  236. set filtOptsMenu "filterOptions"
  237.  
  238. menu -n $perlMenu [ concat {
  239.         "/'<Umacperl"
  240.         {menu -m -n "tellMacperl..." -p perlTellProc {
  241.            "/O<UOpen This File"
  242.            "Save As Droplet"
  243.            "Save As Runtime"
  244.            "Save As CGI"
  245.             "(-"
  246.            "Get Output Window"
  247.            "Close Output Window"
  248.            "Quit"
  249.            }
  250.         } 
  251.         {menu -m -n help -p perlHelpProc {
  252.             "MacPerl Mode"
  253.             "Mac Specifics"
  254.             "Perl4 Commands"
  255.             "Perl5 Manual"
  256.         }}
  257.         perlPalette
  258.         "(-"
  259.         "runTheSelection"
  260.         "/R<UrunTheBuffer"
  261.         "/R<B<OsaveAndRun"
  262.         "runAFile"
  263.         "(-"
  264.     } [list [list menu -n $perlFilterMenu {}]] {
  265.        "selectBufferAsFilter"
  266.        "selectFileAsFilter"
  267.        "/F<UrepeatLastFilter"
  268.        "(-" 
  269.     } [list [list menu -n $perlOptsMenu {}]] {
  270.     } [list [list menu -n $filtOptsMenu {}]] {
  271.     } ]
  272.  
  273. enableMenuItem $perlMenu perlDebugWindow 0
  274. enableMenuItem "tellMacperl..." "Save As CGI" 0
  275.  
  276. if {$perlPrevScript == {} || $perlPrevScript == {*startup*}} {
  277.     enableMenuItem $perlMenu repeatLastFilter 0
  278. }
  279.  
  280. # General Perl-menu options menu
  281. #
  282. menu -n $perlOptsMenu {
  283.     "retrieveOutput"
  284.     "autoSwitch"
  285.     "promptForArgs"
  286.     "useDebugger"
  287.     }    
  288. markMenuItem $perlOptsMenu useDebugger $perlUseDebug
  289. markMenuItem $perlOptsMenu retrieveOutput $perlGetOutput
  290. markMenuItem $perlOptsMenu autoSwitch $perlAutoSwitch
  291. markMenuItem $perlOptsMenu promptForArgs $perlPromptArgs
  292.  
  293. # Text Filter options menu
  294. #
  295. menu -n $filtOptsMenu {
  296.     "applyToBuffer"
  297.     "overwriteSelection"
  298.     "(-"
  299.     "textFiltersFolder"
  300.     "rebuildFilterMenu"
  301.     }    
  302. markMenuItem $filtOptsMenu overwriteSelection $perlOverwrite
  303. markMenuItem $filtOptsMenu applyToBuffer $perlUsebuffer
  304.  
  305.  
  306. #############################################################################
  307. #  Build a submenu of "preattached" Perl filters using the names of the 
  308. #  scripts in the Text Filters directory.  Called whenever Text Filters
  309. # folder is reassigned.
  310. #
  311. proc rebuildFilterMenu {{args}} {
  312.     global perlFilters perlFilterMenu perlFilterPath
  313.     global $perlFilterMenu
  314.     
  315.     eval [buildSubMenu [list $perlFilterPath] $perlFilterMenu textFiltersProc perlFilters]
  316. }
  317.  
  318. rebuildFilterMenu
  319.  
  320. #############################################################################
  321. # Use variable tracing to keep global vars and modeVars consistent.
  322. #
  323. trace variable PerlmodeVars(perlUseDebug) w shadowPerl
  324. trace variable PerlmodeVars(perlOverwrite) w shadowPerl
  325. trace variable PerlmodeVars(perlUsebuffer) w shadowPerl
  326. trace variable PerlmodeVars(perlGetOutput) w shadowPerl
  327. trace variable PerlmodeVars(perlAutoSwitch) w shadowPerl
  328. trace variable PerlmodeVars(perlPromptArgs) w shadowPerl
  329. trace variable PerlmodeVars(perlLastFilter) w shadowPerl
  330. trace variable PerlmodeVars(perlCmdlineArgs) w shadowPerl
  331. trace variable PerlmodeVars(perlRecycleOutput) w shadowPerl
  332. trace variable PerlmodeVars(perlVersion) w shadowPerl
  333.  
  334. # perlFilterPath is now just a regular variable, set from the App Paths submenu
  335. trace variable perlFilterPath w rebuildFilterMenu
  336.  
  337. # ShadowPerl sets the global vars when the mode vars are modified and
  338. # keeps the menu checkmarked correctly.
  339. #
  340. proc shadowPerl {name1 name2 op} {
  341.     global HOME perlMenu perlOptsMenu filtOptsMenu
  342.     global perlOverwrite perlUsebuffer perlGetOutput perlAutoSwitch
  343.     global perlPromptArgs perlPrevScript perlCmdlineArgs perlUseDebug
  344.     global PerlmodeVars
  345.     if {$name1 == "PerlmodeVars" && $op == "w"} {
  346.         switch $name2 {
  347.             "perlUseDebug"    {
  348.                 set perlUseDebug $PerlmodeVars(perlUseDebug)
  349.                 markMenuItem $perlOptsMenu useDebugger $perlUseDebug
  350.              }
  351.             "perlOverwrite"    {
  352.                 set perlOverwrite $PerlmodeVars(perlOverwrite)
  353.                 markMenuItem $filtOptsMenu overwriteSelection $perlOverwrite
  354.              }
  355.             "perlUsebuffer"    {
  356.                 set perlUsebuffer $PerlmodeVars(perlUsebuffer)
  357.                 markMenuItem $filtOptsMenu applyToBuffer $perlUsebuffer
  358.              }
  359.             "perlGetOutput"    {
  360.                 set perlGetOutput $PerlmodeVars(perlGetOutput)
  361.                 markMenuItem $perlOptsMenu retrieveOutput $perlGetOutput 
  362.             }
  363.             "perlAutoSwitch" {    
  364.                 set perlAutoSwitch $PerlmodeVars(perlAutoSwitch)
  365.                 markMenuItem $perlOptsMenu autoSwitch $perlAutoSwitch 
  366.             }
  367.             "perlPromptArgs" {    
  368.                 set perlPromptArgs $PerlmodeVars(perlPromptArgs)
  369.                 markMenuItem $perlOptsMenu promptForArgs $perlPromptArgs 
  370.             }
  371.             "perlCmdlineArgs" {    
  372.                 set perlCmdlineArgs $PerlmodeVars(perlCmdlineArgs)
  373.             }
  374.             "perlRecycleOutput" {    
  375.                 set perlRecycleOutput $PerlmodeVars(perlRecycleOutput)
  376.             }
  377.             "perlVersion" {    
  378.                 set perlVersion $PerlmodeVars(perlVersion)
  379.                 set modeCode ":Tcl:Modes:perl${perlVersion}.tcl"
  380.                 if {[catch {source $HOME$modeCode}]} {
  381.                     alertnote "Couldn't load the Perl-mode colorization file ¥"$modeCode¥".  Contact the maintainer."
  382.                 }
  383.             }
  384.             "perlLastFilter" {    
  385.                 # Don't allow perlPrevScript to be changed from the flags menu
  386.                 if {$perlPrevScript == "*startup*"} {
  387.                     set perlPrevScript $PerlmodeVars(perlLastFilter)
  388.                     enableMenuItem $perlMenu repeatLastFilter 1
  389.                 } else {
  390.                     set PerlmodeVars(perlLastFilter) $perlPrevScript 
  391.                 }
  392.             }
  393.             default {
  394.                 return
  395.             }
  396.         }
  397.     }
  398. }
  399.  
  400. #############################################################################
  401. # Menu commands
  402. #############################################################################
  403.  
  404. ############################################################################
  405. # Toggle the perl menu flags
  406. #
  407. proc retrieveOutput {} {
  408.     global perlMenu PerlmodeVars perlGetOutput modifiedModeVars
  409.     lappend modifiedModeVars [list perlGetOutput PerlmodeVars]
  410.     if {$perlGetOutput} then {
  411.         set PerlmodeVars(perlGetOutput) 0
  412.     } else {
  413.         set PerlmodeVars(perlGetOutput) 1
  414.     }
  415. }
  416.  
  417. proc useDebugger {} {
  418.     global perlMenu PerlmodeVars perlUseDebug modifiedModeVars
  419.     lappend modifiedModeVars [list  perlUseDebug PerlmodeVars]
  420.     if {$perlUseDebug} then {
  421.         set PerlmodeVars(perlUseDebug) 0
  422.     } else {
  423.         set PerlmodeVars(perlUseDebug) 1
  424.     }
  425. }
  426.  
  427. proc autoSwitch {} {
  428.     global perlMenu PerlmodeVars perlAutoSwitch modifiedModeVars
  429.     lappend modifiedModeVars [list  perlAutoSwitch PerlmodeVars]
  430.     if {$perlAutoSwitch} then {
  431.         set PerlmodeVars(perlAutoSwitch) 0
  432.     } else {
  433.         set PerlmodeVars(perlAutoSwitch) 1
  434.     }
  435. }
  436.  
  437. proc overwriteSelection {} {
  438.     global perlMenu perlOverwrite PerlmodeVars modifiedModeVars
  439.     lappend modifiedModeVars [list  perlOverwrite PerlmodeVars]
  440.     if {$perlOverwrite} then {
  441.         set PerlmodeVars(perlOverwrite) 0
  442.     } else {
  443.         set PerlmodeVars(perlOverwrite) 1
  444.     }
  445. }
  446.  
  447. proc applyToBuffer {} {
  448.     global perlMenu perlUsebuffer PerlmodeVars modifiedModeVars
  449.     lappend modifiedModeVars [list  perlUsebuffer PerlmodeVars]
  450.     if {$perlUsebuffer} then {
  451.            set PerlmodeVars(perlUsebuffer) 0
  452.     } else {
  453.            set PerlmodeVars(perlUsebuffer) 1
  454.     }
  455. }
  456.  
  457. proc promptForArgs {} {
  458.     global perlMenu perlPromptArgs PerlmodeVars modifiedModeVars
  459.     lappend modifiedModeVars [list perlPromptArgs PerlmodeVars]
  460.     if {$perlPromptArgs} then {
  461.            set PerlmodeVars(perlPromptArgs) 0
  462.     } else {
  463.            set PerlmodeVars(perlPromptArgs) 1
  464.     }
  465. }
  466.  
  467. proc textFiltersFolder {} {
  468.     global perlMenu perlFilterPath PerlmodeVars modifiedModeVars pathComments
  469.     
  470.     pathProc {} $pathComments(perlFilterPath)
  471. }
  472.  
  473. #############################################################################
  474. # Switch to MacPerl:
  475. proc macperl {} {
  476.     launchForeAppl McPL
  477. }
  478.  
  479. #############################################################################
  480. # Interact with MacPerl in some other way besides executing a script
  481. #
  482. proc perlTellProc {menu name} {
  483.     switch -exact $name {
  484.     "Open This File"        { openInMacperl }
  485.     
  486.     "Save As Droplet"        { saveThruMacperl "droplet" }
  487.     
  488.     "Save As Runtime"        { saveThruMacperl "runtime" }
  489.     
  490.     "Save As CGI"            { saveThruMacperl "cgi" }
  491.     
  492.     "Save As CGI-not"        { saveThruMacperl "cgi-not" }
  493.     
  494.     "Get Output Window"        { openPerlOutput }
  495.     
  496.     "Close Output Window"    { sendCloseWinName MacPerl MacPerl ;
  497.                               sendCloseWinName MacPerl "Perl Debug" }
  498.                             
  499.     "Quit"                    { quitMacperl }
  500.     }
  501. }
  502.  
  503. #############################################################################
  504. # Open the current file under MacPerl.  This used to useful for saving files 
  505. # as droplets or runtime scripts.  Maybe it's still useful for something...?
  506. #
  507. proc openInMacperl {} {
  508.     if {[winDirty]} {
  509.         case [askyesno -c "Save '[lindex [winNames] 0]'?"] in {
  510.             "yes" {save}
  511.             "no" {}
  512.             "cancel" {return}
  513.         }
  514.     }
  515.     set name [launchForeAppl McPL]
  516.     sendOpenEvent -n [file tail $name] [car [winNames -f]]
  517. }
  518.  
  519. #############################################################################
  520. # Save the script in the current window as a MacPerl droplet or 
  521. # runtime script.  
  522. #
  523. proc saveThruMacperl {type} {
  524.     global ALPHA
  525.  
  526.     set name [file tail [launchBackAppl McPL]]
  527.     getWinInfo arr
  528.     if {$arr(dirty) == 1} {
  529.         case [askyesno -c "Save '[lindex [winNames] 0]' source file also?"] in {
  530.             "yes" {save}
  531.             "no" {}
  532.             "cancel" {return}
  533.         }
  534.     }
  535.  
  536.     set destfile [AEFilename [putfile {Save droplet as} [lindex [winNames] 0]]]
  537.  
  538.     set script [curlyq [getText 0 [maxPos]]]
  539.  
  540.     if {$type == "droplet"} {
  541.         set saveType "SCPT"
  542.     } elseif {$type == "runtime"} {
  543.         set saveType "MrP7"
  544.     } elseif {$type == "cgi"} {
  545.         set saveType "WWWス"
  546.     } elseif {$type == "cgi-not"} {
  547.         set saveType "WWWO"
  548.     } elseif {$type == "text"} {
  549.         set saveType "TEXT"
  550.     }
  551.     
  552.     set err [catch {eval "AEBuild -t 36000 -r ¥"$name¥"" core save {----} [list $script] {dest:} [list $destfile] {fltp:} $saveType } reply ]
  553.     if {$err} { message "AEBuild error code $err in saveThruMacperl" }
  554.     
  555. # The following lines could be used to tell MacPerl to take the script file 
  556. # from an existing disk file and then re-save it in the desired form.
  557. #
  558. #    set srcfile "¥[ [AEFilename [car [winNames -f]]] ¥]"
  559. #    set reply [eval "AEBuild -t 36000 -r ¥"$name¥"" core save {----} [list $srcfile] {dest:} [list $destfile] {fltp:} $saveType ]
  560. #
  561. }
  562.  
  563. #############################################################################
  564. # Quit a running MacPerl app:
  565. proc quitMacperl {} {
  566.     foreach proc [processes] {
  567.         set sig [lindex $proc 1]
  568.         if {$sig == "McPL"} {
  569.             sendQuitEvent [lindex $proc 0]
  570.             # switchTo is necessary to keep MacPerl from blinking
  571.             switchTo [lindex $proc 0]    
  572.         }
  573.     }
  574. }
  575.  
  576. #############################################################################
  577. # Run the selection as a MacPerl script:
  578. # (No special arrangements are made to provide input or capture the output)
  579. proc runTheSelection {} {
  580.     global scriptFile scriptStart
  581.     set scriptFile [car [winNames -f]]
  582.     set scriptStart [lindex [posToRowCol [getPos]] 0]
  583.     perlExecuteScript [getSelect]
  584. }
  585.  
  586. proc runTheBuffer {} {
  587.     global scriptFile scriptStart
  588.     set scriptFile [car [winNames -f]]
  589.     set scriptStart 1
  590.     perlExecuteScript [getText 0 [maxPos]]
  591. }
  592.  
  593. proc runAFile {} {
  594.     global scriptFile scriptStart
  595.     if {! [catch {getfile "Select a Perl script"} path]} {
  596.         set scriptFile $path
  597.         set scriptStart 1
  598.         perlExecuteFile $path
  599.     }
  600. }
  601.  
  602. proc saveAndRun {} {
  603.     global scriptFile scriptStart
  604.     save
  605.     set path [car [winNames -f]]   
  606.     set scriptFile $path
  607.     set scriptStart 1
  608.     perlExecuteFile $path
  609. }
  610.  
  611. #############################################################################
  612. # Run a preattached Perl text-filter script selected from the menu:
  613. #
  614. proc textFiltersProc {menu name} {
  615.     global perlFilters scriptFile scriptStart
  616.     
  617.     perlFileAsFilter $perlFilters($menu:$name)
  618. }
  619.  
  620. #############################################################################
  621. # Reuse the previous (buffer or file) filter:
  622. #
  623. proc repeatLastFilter {} {
  624.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  625.     if {$perlPrevScript != {}} {
  626.         set stype [lindex $perlPrevScript 0]
  627.         set name [lindex $perlPrevScript 1]
  628.         if {$stype == "file"} {
  629.             perlFileAsFilter $name
  630.         } elseif {$stype == "buffer"} {
  631.             perlBufferAsFilter $name
  632.         } else {
  633.             message "Bogus filter name : ¥"$perlPrevScript¥""
  634.             set perlPrevScript {}
  635.             set PerlmodeVars(perlLastFilter) $perlPrevScript 
  636.             enableMenuItem $perlMenu repeatLastFilter 0
  637.         }
  638.     }
  639. }
  640.  
  641. #############################################################################
  642. # Ask for a file containing a Perl script to use as a filter:
  643. #
  644. proc selectFileAsFilter {} {
  645.     global scriptFile scriptStart perlPrevScript
  646.     if {! [catch {getfile "Select a MacPerl script"} path]} {
  647.         perlFileAsFilter $path
  648.     }
  649. }
  650.  
  651. #############################################################################
  652. # Ask for an Alpha buffer containing a Perl script to use as a filter:
  653. #
  654. proc selectBufferAsFilter {} {
  655.     global scriptFile scriptStart perlPrevScript
  656.     
  657.     set windows [winNames]
  658.     set current [lindex $windows 0]
  659.     if {[llength $windows] > 1} {
  660.         set name [listpick [lsort $windows]]
  661.         if {[string length $name]} {
  662.             # get the full name of the chosen window
  663.             set wname [lindex [winNames -f] [lsearch -exact $windows $name]]
  664.             perlBufferAsFilter $wname
  665.            }
  666.     }
  667. }
  668.  
  669. #############################################################################
  670. # Open a file from the MacPerl application folder - used by "Open Special"
  671. #
  672. proc perlOpenFile {menu name} {
  673.     set filename [macperlFolder]$name
  674.     if {[file exists $filename]} {
  675.         edit $filename
  676.     } else {
  677.         alertnote "That file doesn't exist yet"
  678.     }
  679. }
  680.  
  681. #############################################################################
  682. # Support procs
  683. #############################################################################
  684.  
  685. #############################################################################
  686. # Prompt the user to enter a string containing command-line args.
  687. #
  688. proc getCmdlineArgs {} {
  689.     global PerlmodeVars
  690.     set oldargs $PerlmodeVars(perlCmdlineArgs)
  691.     if {![catch {prompt "Command-line arguments (if any):" $oldargs} args]} {
  692.         set PerlmodeVars(perlCmdlineArgs) $args
  693.     } else {
  694.         error "getCmdlineArgs: User cancelled"
  695.     }
  696.     return $args
  697. }
  698.  
  699. #############################################################################
  700. # Tell MacPerl to run a script file:
  701. #
  702. proc perlExecuteFile {path {args {}} {flags {}}} {
  703.     global ALPHA
  704.     global perlGetOutput perlAutoSwitch perlPromptArgs perlUseDebug
  705.     global scriptFile scriptStart filterHeadLen
  706.     
  707.     if {[string length $path]} {
  708.         set name [file tail [launchBackAppl McPL]]
  709.         if {[string length $name]} {
  710.                 
  711.             set ok [regexp {(.*):([^:]*)} $path pathname dirname filename]
  712.             if {!$ok} {    set name $wname    }
  713.  
  714.             if {$path != [scriptPath]} {    
  715.                 set filterHeadLen 0    
  716.             }
  717.             
  718.             if {$perlUseDebug} {
  719.                 append flags "debug"
  720.             }
  721.             if {$perlPromptArgs} { 
  722.                 append args " [getCmdlineArgs]"
  723.             }
  724.             
  725.             sendCloseWinName MacPerl MacPerl
  726.             sendCloseWinName MacPerl "Perl Debug"
  727.             if {$perlAutoSwitch || $perlUseDebug} then {
  728.                 switchTo $name
  729.             } else {
  730.                 message "Running file ¥"$filename¥" as Perl script"
  731.                 watchCursor
  732.             }
  733.             
  734.             perlDoScript "MacPerl" $path $args {} $flags
  735.             
  736. # (not sure which choice is better...)
  737. #            if {!$perlAutoSwitch} then {switchTo $ALPHA}
  738.             switchTo $ALPHA
  739. #
  740.             if {![getMacPerlError]} {
  741.                 if {$perlGetOutput} then {openPerlOutput}
  742.             }
  743.         } else {
  744.             alertnote "Couldn't run MacPerl"
  745.         }
  746.     } else {
  747.         alertnote "No file specified to execute"
  748.     }
  749. }
  750.  
  751. #############################################################################
  752. # Run a MacPerl script, passed explicitly as a string:
  753. #
  754. # If no "#!/bin/perl" line already exists, one is preprended to the script
  755. # by wrapSelectScript, which also sets $filterHeadLen for use by 
  756. # getMacPerlError.
  757. proc perlExecuteScript {script {args ""} {flags {}} } {
  758.     global perlGetOutput perlAutoSwitch perlPromptArgs
  759.     global scriptFile scriptStart filterHeadLen perlUseDebug ALPHA
  760.     
  761.     if {$script != ""} {
  762.         set script [wrapSelectScript $script]
  763.         
  764.         if {![regexp {(.*):([^:]*)} $scriptFile pathname dirname filename]} {
  765.             set filename $scriptFile 
  766.         }
  767.  
  768.         set name [file tail [launchBackAppl McPL]]
  769.         if {[string length $name]} {
  770.         
  771.             if {$perlUseDebug} {
  772.                 append flags "debug"
  773.             }
  774.             if {$perlPromptArgs} { 
  775.                 append args " [getCmdlineArgs]"
  776.             }
  777.             
  778.             sendCloseWinName MacPerl MacPerl
  779.             sendCloseWinName MacPerl "Perl Debug"
  780.             if {$perlAutoSwitch || $perlUseDebug} then {
  781.                 switchTo $name
  782.             } else {
  783.                 message "Running buffer ¥"$filename¥" as Perl script"
  784.                 watchCursor
  785.             }
  786.             
  787.             perlDoScript "MacPerl" $script $args {} $flags
  788.             
  789.             switchTo $ALPHA
  790.  
  791.             if {![getMacPerlError]} {
  792.                 if {$perlGetOutput} then {openPerlOutput}
  793.             }
  794.         }
  795.         
  796.     } else {
  797.             alertnote "Can't run an empty script"
  798.     }
  799. }
  800.  
  801. #############################################################################
  802. # Prepare the contents of a disk file for use as a text-filter script. 
  803. # (calls perlTextFilter to actually run the script)
  804. proc perlFileAsFilter {path} {
  805.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  806.     
  807.     regexp {(.*):([^:]*)} $path pathname dirname name
  808.     
  809.     if {![catch {readFile $path} coreScript]} {
  810.         set script [wrapFilterScript $coreScript]
  811.         set scriptFile $path
  812.         set scriptStart 1
  813.         set perlPrevScript [list "file" $path]
  814.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  815.         enableMenuItem $perlMenu repeatLastFilter 1
  816.         message "Running file ¥"$name¥" as text filter ..."
  817.         
  818.         perlTextFilter $script
  819.     } else {
  820.         set perlPrevScript {}
  821.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  822.         enableMenuItem $perlMenu repeatLastFilter 0
  823.         
  824.         alertnote "Couldn't read the script file : $path"
  825.         return
  826.     }
  827. }
  828.  
  829. #############################################################################
  830. # Prepare the contents of a text window for use as a text-filter script. 
  831. # (calls perlTextFilter to actually run the script)
  832. proc perlBufferAsFilter {wname} {
  833.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  834.  
  835.     set ok [regexp {(.*):([^:]*)} $wname pathname dirname name]
  836.     if {!$ok} {    set name $wname    }
  837.     
  838.     if {[lsearch [winNames -f] $wname] >= 0} {
  839.         set coreScript [getText -w $wname 0 [maxPos -w $wname]]
  840.         
  841.         # Does it have any text in it?
  842.         if {[string length $coreScript]} {
  843.             set scriptFile $wname
  844.             set scriptStart 1
  845.             set script [wrapFilterScript $coreScript]
  846.             set perlPrevScript [list "buffer" $wname]
  847.             set PerlmodeVars(perlLastFilter) $perlPrevScript 
  848.             enableMenuItem $perlMenu repeatLastFilter 1
  849.             message "Running buffer ¥"$name¥" as text filter ..."
  850.             
  851.             perlTextFilter $script
  852.         }
  853.     } else {
  854.         set perlPrevScript {}
  855.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  856.         enableMenuItem $perlMenu repeatLastFilter 0
  857.  
  858.         alertnote "Couldn't find buffer : $name"
  859.     }
  860. }
  861.  
  862. #############################################################################
  863. # Run a Perl script as a command-line text filter, arranging for a text
  864. # buffer to be attached as standard input.  The calling routine should already
  865. # have processed the script with wrapFilterScript.  This routine actually
  866. # send the script and takes care of writing the input and reading the output 
  867. # files.
  868. proc perlTextFilter {script {args {}} {flags {}}} {
  869.     global perlOverwrite perlUsebuffer perlPromptArgs
  870.     global filterHeadLen scriptFile scriptStart perlUseDebug ALPHA
  871.     global perlOutputWindow perlRecycleOutput
  872.  
  873.     set name [file tail [launchBackAppl McPL]]
  874.     if {![string length $name]} {
  875.         alertnote "Couldn't run MacPerl"
  876.         error "Couldn't run MacPerl"
  877.     }
  878.     writeStdin
  879.  
  880.     if {$perlUseDebug} {
  881.         append flags "debug"
  882.     }
  883.     if {$perlPromptArgs} { 
  884.         append args " [getCmdlineArgs]"
  885.     }
  886.     
  887.     sendCloseWinName MacPerl MacPerl
  888.     sendCloseWinName MacPerl "Perl Debug"
  889.     
  890.     if {$perlUseDebug} then {
  891.         switchTo $name
  892.         perlDoScript "MacPerl" [scriptPath] $args [list [stdinPath]] $flags
  893.         set err [getMacPerlError]
  894.  
  895.     } else {
  896.         watchCursor
  897.         set reply [perlDoScriptBatch "MacPerl" [scriptPath] $args [list [stdinPath]]]
  898.         set err [getBatchError $reply]
  899.     }
  900.     
  901.     switchTo $ALPHA
  902.     
  903.     if {$err == 0} {
  904.         if {$perlUseDebug} {
  905.             set outp [sendGetText MacPerl MacPerl]
  906.         } else {
  907. #            set outp [parseReplyOutp $reply]
  908.             set outp [parseReplyResult $reply]
  909.         }
  910.         pasteFilterResult $outp
  911.     }
  912. }
  913.  
  914.  
  915. #############################################################################
  916. # Check the MacPerl output window for error messages.
  917. #
  918. proc getMacPerlError {} {
  919.     
  920.     set diag [getPerlDiag 40]
  921.     set srcs [parseDiagSrcs $diag]
  922.     set errf [parseDiagErrf $diag]
  923.     set mesg [parseDiagMesg $diag]
  924.  
  925.     if {[string length $errf]} {
  926.         showPerlDiag $diag [string length $diag] $mesg $errf $srcs
  927.         gotoPerlError $errf $srcs $mesg
  928.         return 1
  929.         
  930.     } else {
  931.         return 0
  932.     }
  933. }
  934.  
  935. #############################################################################
  936. # Check the MacPerl batch reply for error messages.
  937. #
  938. proc getBatchError {reply} {
  939.     global perlErrorWindow
  940.     
  941.     set fatalError 0
  942.     set diag [parseReplyDiag $reply]
  943.     set errf [parseDiagErrf  $diag ]
  944.     set srcs [parseReplySrcs $reply]
  945.     set mesg [parseDiagMesg  $diag ]
  946.     set errn [parseReplyErrn $reply]
  947.  
  948.     if {$errn} {        
  949.         showPerlDiag $diag $errn $mesg $errf $srcs
  950.         gotoPerlError $errf $srcs $mesg
  951.         set fatalError 1
  952.         
  953.     } elseif {[string length $diag] > 0} {
  954.         showPerlDiag $diag $errn $mesg $errf $srcs
  955.     }
  956.     
  957.     return $fatalError
  958. }
  959.  
  960. #############################################################################
  961. # Display the Perl diagnostic output in its own window.
  962. #
  963. proc showPerlDiag {diag {errn 1} {mesg {}} {errf {}} {srcs {}}} {
  964.         global perlErrorWindow    
  965.         
  966.         set currWin [lindex [winNames] 0]
  967.         if {[lsearch [winNames] $perlErrorWindow] >= 0} {
  968.             bringToFront $perlErrorWindow
  969.             setWinInfo read-only 0
  970.             deleteText 0 [maxPos] 
  971.             insertText $diag
  972.         } else {
  973.             new -n $perlErrorWindow 
  974.              insertText $diag
  975.         }
  976.         
  977.         goto 0
  978.         catch {shrinkWindow 2}
  979.         setWinInfo dirty 0
  980.         setWinInfo read-only 1
  981.         bringToFront $currWin
  982. }
  983.  
  984. #############################################################################
  985. # Bring up a window containing the bug-ridden Perl code and highlight the
  986. # line at which the error was found.
  987. #
  988. proc gotoPerlError {errf srcs {mesg {}}} {
  989.     global scriptFile scriptStart filterHeadLen
  990.  
  991.     if {$errf == [scriptPath] || $errf == "<AppleEvent>"} {
  992.         set errf $scriptFile
  993.         # Convert it to the line number in the original file
  994.         set srcs [expr $srcs + $scriptStart - $filterHeadLen - 1]
  995.     }
  996.     # ... and leave an informative error message
  997.     #
  998.     if {[string length $mesg]} {
  999.         set mesg "$mesg at Line $srcs"            
  1000.     } else {
  1001.         set mesg "MacPerl flagged an error at Line $srcs"    
  1002.     }
  1003.     
  1004.     # Bring up the script file and highlight the flagged line
  1005.     #
  1006.     catch {gotoFileLine $errf $srcs $mesg} fname    
  1007. }
  1008.  
  1009. #############################################################################
  1010. # Read the first block of lines (up to a maximum number) from the MacPerl
  1011. # output window.
  1012. #
  1013. proc getPerlDiag {maxlines} {
  1014.     set pat0 {^[ ¥t]*$}
  1015.  
  1016.     set lines {}    
  1017.  
  1018.     # read first $maxlines of output to the MacPerl window
  1019.     # (faster, but assumes error message won't appear at 
  1020.     # the end of a lot of output).
  1021.     #
  1022.     set nlines [sendCountLines MacPerl MacPerl]
  1023.     set nlines [expr ($nlines > $maxlines)?$maxlines:$nlines]
  1024.     if {$nlines > 0} {
  1025.         set output [sendGetText MacPerl MacPerl 1 $nlines]
  1026.         
  1027.         foreach line [split $output "¥r"] {
  1028.             if  {[regexp $pat0 $line mtch]} {
  1029.                 break
  1030.             } else {
  1031.                 append lines "$line¥n"
  1032.             }
  1033.         }
  1034.     }
  1035.     return $lines
  1036. }
  1037.  
  1038. #############################################################################
  1039. # Extract various items out of the MacPerl diagnostic output
  1040. #
  1041.  
  1042. # Name of the file in which the error was found
  1043. #
  1044. proc parseDiagErrf {diag}    {
  1045.     if {![regexp {File '([^']+)'; Line} $diag allofit errf]} { 
  1046.         set errf {}
  1047.     }
  1048.     return $errf
  1049. }
  1050.  
  1051. # The line number on which the error was found
  1052. #
  1053. proc parseDiagSrcs {diag}    {
  1054.     if {![regexp {File '[^']+'; Line ([0-9]+)} $diag allofit srcs]} { 
  1055.         set srcs 0 
  1056.     }
  1057.     return $srcs
  1058. }
  1059.  
  1060. # The error message associated with error
  1061. #
  1062. proc parseDiagMesg {diag} {
  1063.     set pat1 {^#(.*)$}
  1064.     set pat2 {File '([^']+)'; Line ([0-9]+)}
  1065.     
  1066.     set errMessage {}
  1067.     set errFound 0
  1068.     
  1069.     foreach line [split $diag "¥n"] {
  1070.         if {[regexp $pat2 $line mtch num]} {
  1071.             set errFound 1
  1072.         } elseif {[regexp $pat1 $line mtch err]} {
  1073.             if {$errFound == 0} {
  1074.                 set errMessage $err
  1075.             }
  1076.         }
  1077.     }
  1078.     return $errMessage
  1079. }
  1080.  
  1081. #############################################################################
  1082. # Extract various return parameters out of a MacPerl DoScript reply
  1083. #
  1084.  
  1085. # Result from batch script
  1086. #
  1087. proc parseReplyResult {reply} {
  1088.     if {![regexp {'?¥-¥-¥-¥-'?:メ([^モ]*)モ} $reply allofit result]} { 
  1089.         set result {}
  1090.     }
  1091.     return $result
  1092. }
  1093.  
  1094. # Standard output of batch script
  1095. #
  1096. proc parseReplyOutp {reply} {
  1097.     if {![regexp {OUTP:メ([^モ]*)モ} $reply allofit outp]} { 
  1098.         set outp {}
  1099.     }
  1100.     return $outp
  1101. }
  1102.  
  1103. # Diagnostic output of the batch script
  1104. #
  1105. proc parseReplyDiag {reply}    {
  1106.     if {[regexp {diag:メ([^モ]*)モ} $reply allofit diag]}  {
  1107.     } else { 
  1108.         set diag {}
  1109.     }
  1110.     return $diag
  1111. }
  1112.  
  1113. # File alias of the script file in which the error was found
  1114. #
  1115. proc parseReplyErob {reply}    {
  1116.     if {![regexp {erob:alis¥(ヌ(.*)ネ¥)} $reply allofit erob]} {
  1117.         set erob {} 
  1118.     }
  1119.     return $erob
  1120. }
  1121.  
  1122. # First line flagged in error
  1123. #
  1124. proc parseReplySrcs {reply}    {
  1125.     if {![regexp {erng:{srcs:([0-9]+)[^¥}]*}} $reply allofit srcs]} { 
  1126.         set srcs 0 
  1127.     }
  1128.     return $srcs
  1129. }
  1130.  
  1131. # Last line flagged in error
  1132. #
  1133. proc parseReplySrce {reply}    {
  1134.     if {![regexp {erng:{[^¥}]*srce:([0-9]+)}} $reply allofit srce]} { 
  1135.         set srce 0
  1136.     }
  1137.     return $srce
  1138. }
  1139.  
  1140. # Error number
  1141. #
  1142. proc parseReplyErrn {reply}    {
  1143.     if {![regexp {errn:([0-9]+)} $reply allofit errn]} {
  1144.         set errn 0
  1145.     }
  1146.     return $errn
  1147. }
  1148.  
  1149. #############################################################################
  1150. #  Take a Perl script and add commands to take the file STDIN as standard
  1151. #  input and STDOUT as standard output.  This allows scripts written as
  1152. #  Unix command-line filters to be used in the (non-MPW) Mac environment as
  1153. #  text filters.
  1154. #
  1155. #  If there's already a #! line in the script, then the new commands
  1156. #  are added after that line.  If there was no #! line in the first place,
  1157. #  one is added, in case MacPerl is set up to require it (can't hurt...) 
  1158. #
  1159. #  $filterHeadLen counts the number of lines we add to the top of the
  1160. #  original script, so that we can allow for it in interpreting error
  1161. #  messages issued by MacPerl.
  1162. #
  1163. #  *** As of MacPerl 4.1.4, this business is pretty much obsolete ***
  1164. #
  1165. proc wrapFilterScript {coreScript} {
  1166.     global filterHeadLen
  1167.  
  1168.     if {[regexp -indices {(#![     !-~]*)} $coreScript allofit cmdln]} {
  1169.         set endPos [lindex $cmdln 1]
  1170.         set filterHead [string range $coreScript 0 [expr $endPos+1]]
  1171.         set coreScript [string range $coreScript [expr $endPos+2] end]
  1172.         set filterHeadLen 0
  1173.     } else {
  1174.         set filterHead "#!/bin/perl¥n¥r"
  1175.         set filterHeadLen 2
  1176.     }
  1177.         
  1178.     set script $filterHead
  1179.     append script $coreScript
  1180.     
  1181.     # for debugging purposes, save the script on disk
  1182.     #
  1183.     writeScript $script
  1184.     return $script
  1185. }        
  1186.  
  1187. #############################################################################
  1188. #  Add a #!/bin/perl line to the script if it doesn't contain one already.
  1189. #  (MacPerl puts up dialog if this line is missing when it expects it,
  1190. #  hanging the DoScript and leaving us stuck.)
  1191. #
  1192. proc wrapSelectScript {coreScript} {
  1193.     global filterHeadLen
  1194.  
  1195.     if {![regexp -indices {(#![     !-~]*)} $coreScript allofit cmdln]} {
  1196.         set script "#!/bin/perl¥r¥n"
  1197.         append script $coreScript
  1198.         set filterHeadLen 1
  1199.     } else {
  1200.         set script $coreScript
  1201.         set filterHeadLen 0
  1202.     }
  1203.     
  1204.     # for debugging purposes, save the script on disk
  1205.     #
  1206.     writeScript $script
  1207.     return $script
  1208. }        
  1209.  
  1210. #############################################################################
  1211. #  Paste result of the filter operation in place of the input text, or in
  1212. #  a new window (depending on the flag $perlOverwrite
  1213. #
  1214. proc pasteFilterResult {text} {
  1215.     global perlOverwrite perlRecycleOutput perlOutputWindow
  1216.     global perlUsebuffer 
  1217.     
  1218.     if {!$perlOverwrite} {
  1219.         if {$perlRecycleOutput && 
  1220.             [lsearch [winNames] $perlOutputWindow] >= 0} {                
  1221.             bringToFront $perlOutputWindow
  1222.         } else {
  1223.             new -n $perlOutputWindow
  1224.         }
  1225.     }
  1226.     
  1227.     if {$perlUsebuffer || $perlRecycleOutput} {
  1228.         set from 0
  1229.         set to [maxPos]
  1230.     } else {
  1231.         set from [getPos] 
  1232.         set to [selEnd]
  1233.     }    
  1234.     replaceText $from $to $text
  1235.     
  1236.     if {!$perlOverwrite || $perlUseBuffer} {
  1237.         catch {shrinkWindow 2}
  1238.         goto 0
  1239.     } else {
  1240.         catch shrinkWindow
  1241.         goto $from
  1242.     }
  1243.     if {!$perlOverwrite} { setWinInfo dirty 0 }
  1244. }    
  1245.  
  1246. #############################################################################
  1247. #  Extend the current selection to encompass complete lines.  If the 
  1248. #  'applyToBuffer' flag is checked, then the entire buffer is selected.
  1249. #
  1250. proc completeSelection {} {
  1251.     global perlUsebuffer filterInput
  1252.     set filterInput "buffer ¥"[lindex [winNames] 0]¥""
  1253.     if {$perlUsebuffer} {
  1254.         set start 0
  1255.         set end [maxPos]
  1256.     } else {
  1257.         set start [lineStart [getPos]]
  1258.         set end [nextLineStart [expr [selEnd]-1]]
  1259.         if {$end == $start} { set end [nextLineStart [selEnd]] }
  1260.         
  1261.         set startLine [lindex [posToRowCol $start] 0]
  1262.         set endLine [expr [lindex [posToRowCol $end] 0] - 1]
  1263.         if {$endLine > $startLine+1} {
  1264.             set filterInput "lines $startLine to $endLine of $filterInput"
  1265.         } else {
  1266.             set filterInput "line $startLine of $filterInput"
  1267.         }
  1268.    }
  1269.     return [list $start $end]
  1270. }
  1271.  
  1272. #############################################################################
  1273. #  writeStdin: Extend the selection, as appropriate, and write it to the 
  1274. #     STDIN file in the MacPerl directory.
  1275. #
  1276. #  writeScript: Write the SCRIPT file in the MacPerl directory.  MacPerl will
  1277. #     read the script from this file. 
  1278. #
  1279. proc writeStdin {} {
  1280.     set res [completeSelection]
  1281.     set tmpfid [open [stdinPath] "w+"]
  1282.     puts $tmpfid [eval getText $res]
  1283.     close $tmpfid
  1284. }
  1285.  
  1286. # This is unnecessary now, but maybe it'll still useful to save the script
  1287. # file for debugging.
  1288. #
  1289. proc writeScript {script} {
  1290.     set tmpfid [open [scriptPath] "w+"]
  1291.     puts $tmpfid $script 
  1292.     close $tmpfid
  1293. }
  1294.  
  1295. #############################################################################
  1296. # Read the MacPerl output window and load the contents, if any, into
  1297. # a new Alpha window. 
  1298. #
  1299. proc openPerlOutput {} {
  1300.     global perlRecycleOutput perlOutputWindow
  1301.     
  1302.     set output [sendGetText MacPerl MacPerl]
  1303.     if {[string length $output]} {
  1304.         if {$perlRecycleOutput && 
  1305.             [lsearch [winNames] $perlOutputWindow] >= 0} {
  1306.             
  1307.             bringToFront $perlOutputWindow
  1308.             replaceText 0 [maxPos] $output
  1309.         } else {
  1310.             new -n $perlOutputWindow
  1311.             insertText $output
  1312.         }
  1313.         catch {shrinkWindow 2}
  1314.         setWinInfo dirty 0
  1315.         goto 0
  1316.     }
  1317. }
  1318.  
  1319. #############################################################################
  1320. # translate special DoScript flags into flags string $usrf
  1321. #
  1322. proc perlScriptFlags {{flags {}}} {
  1323.      set usrf {}
  1324.  
  1325.     if {[lsearch -exact $flags "extract"] >= 0} {
  1326.         append usrf { "EXTR" 'true'}
  1327.     } elseif {[lsearch -exact $flags "noextract"] >= 0} {
  1328.         append usrf { "EXTR" 'fals'}
  1329.     }        
  1330.     if {[lsearch -exact $flags "debug"] >= 0} {
  1331.         append usrf { "DEBG" 'true'}
  1332.     } elseif {[lsearch -exact $flags "nodebug"] >= 0} {
  1333.         append usrf { "DEBG" 'fals'}
  1334.     }        
  1335.  
  1336.     if {[lsearch -exact $flags "local"] >= 0} {
  1337.         append usrf { "MODE" 'LOCL'}
  1338.     } elseif {[lsearch -exact $flags "batch"] >= 0} {
  1339.         append usrf { "MODE" 'BATC'}
  1340.     } elseif {[lsearch -exact $flags "remote"] >= 0} {
  1341.         append usrf { "MODE" 'RCTL'}
  1342.     }        
  1343.     return $usrf
  1344.  
  1345. proc perlScriptArgs {{args {}} {fileargs {}}} {
  1346.     set nargs 0
  1347.     set argv {}
  1348.     
  1349.     foreach item [parseWords $args] {
  1350.         set item [string trim $item]
  1351.         if {[string length $item]} {
  1352.             append argv ", [curlyq $item]"
  1353.             incr nargs
  1354.         }
  1355.     }
  1356.     foreach filename $fileargs {
  1357.         set item [string trim $filename]
  1358.         if {[string length $item]} {
  1359.             append argv ", [curlyq $item]"
  1360.             incr nargs
  1361.         }
  1362.     }
  1363.     return $argv
  1364. }
  1365.  
  1366. #############################################################################
  1367. # General Apple Event routines
  1368. # (most of these have been moved to Modes:appleEvents.tcl)
  1369. #
  1370. # DoScript for MacPerl 4.1.3
  1371. # (runs in "Local" mode under v4.1.4+)
  1372. #
  1373. proc perlDoScript {appname script {args {}} {fileargs {}} {flags {}} } {
  1374.     # form list of quoted "command-line" args
  1375.     #
  1376.     if {$script != ""} {
  1377.         set argv "¥[[curlyq [string trim $script]]"
  1378. #         foreach item [split [join $args " "] " "] {
  1379. #}
  1380.         append argv [perlScriptArgs $args $fileargs]
  1381.         append argv "]"
  1382.         
  1383.         set usrf [perlScriptFlags $flags]
  1384.         set reply [eval "AEBuild -t 36000 -r ¥"$appname¥" misc dosc $usrf ¥"----¥" [list $argv] "]
  1385.     #    alertnote $reply
  1386.     }
  1387. }
  1388.  
  1389. # DoScript for MacPerl 4.1.4+
  1390. #
  1391. proc perlDoScriptBatch {appname script {args {}} {fileargs {}}} {
  1392.     
  1393.     # form list of quoted "command-line" args
  1394.     #
  1395.     if {$script != ""} {
  1396.         set argv "¥[[curlyq [string trim $script]]"
  1397.         append argv [perlScriptArgs $args $fileargs ] 
  1398.         append argv "]"
  1399.                 
  1400.         set reply [eval "AEBuild -t 36000 -r ¥"$appname¥" misc dosc MODE BATC ¥"----¥" [list $argv]"]
  1401.         
  1402. #         perlDisplayReply $reply
  1403.  
  1404.     } else {
  1405.         set reply {}
  1406.     }
  1407.     return $reply
  1408. }
  1409.  
  1410. # For debugging 
  1411. #
  1412. proc perlDisplayReply {reply} {
  1413.     set currWin [lindex [winNames] 0]
  1414.     new -n {*** DoScript Reply **} 
  1415.     insertText $reply
  1416.         
  1417.     goto 0
  1418.     catch {shrinkWindow 2}
  1419.     setWinInfo dirty 0
  1420.     setWinInfo read-only 1
  1421.     bringToFront $currWin
  1422. }
  1423.  
  1424. # DoScript to launch interactive debugger (for MacPerl 4.1.4+)
  1425. #
  1426. proc perlDoScriptDebug {appname script {args {}} {fileargs {}}} {
  1427.     
  1428.     # form list of quoted "command-line" args
  1429.     #
  1430.     if {$script != ""} {
  1431.         set argv "¥[[curlyq [string trim $script]]"
  1432.         append argv [perlScriptArgs "$args debug" $fileargs ] 
  1433.         append argv "]"
  1434.                 
  1435.         set reply [eval "AEBuild -t 36000 -r ¥"$appname¥" misc dosc MODE RCTL ¥"----¥" [list $argv]"]
  1436.  
  1437.         new -n {** DoScriptDebug Reply **} 
  1438.         insertText $reply
  1439.             
  1440.         goto 0
  1441.         catch {shrinkWindow 2}
  1442.         setWinInfo dirty 0
  1443.         setWinInfo read-only 1
  1444.  
  1445.  
  1446.     } else {
  1447.         set reply {}
  1448.     }
  1449.     return $reply
  1450. }
  1451.  
  1452. ##############################################################################
  1453. # Automatic indexing of Perl subs
  1454. #
  1455. proc PerlMarkFile {} {
  1456.     set end [maxPos]
  1457.     set pos 0
  1458.     set l {}
  1459.     while {![catch {search -f 1 -r 1 -m 0 -i 0 {^sub} $pos} res]} {
  1460.         set start [lindex $res 0]
  1461.         set end [nextLineStart $start]
  1462.         set text [lindex [getText $start $end] 1]
  1463.         set pos $end
  1464.         set inds($text) [lineStart [expr $start - 1]]
  1465.     }
  1466.  
  1467.     if {[info exists inds]} {
  1468.         foreach f [lsort [array names inds]] {
  1469.             set next [nextLineStart $inds($f)]
  1470.             setNamedMark $f $inds($f) $next $next
  1471.         }
  1472.     }
  1473. }
  1474.  
  1475.  
  1476. # Open a 'require'd Perl file.
  1477. proc perlFindRequire {from {to 0}} {
  1478.     set reqPat {^[     ]*require[     ]*(¥"[^¥"]+¥"|¥'[^¥']+¥'|[^     ]+)}
  1479.     if {$to == 0} { set to $from }
  1480.     set beg [lineStart $from]
  1481.     set end [nextLineStart $to]
  1482.     set words [parseWords [getText $beg $end]]
  1483.     if {[string tolower [lindex $words 0]] != "require"} {
  1484.         error "Not a require statement"
  1485.     }
  1486.     set root [string trim [lindex $words 1] {'"}]
  1487.     return $root
  1488. }
  1489.  
  1490. proc inlineRequires {} {
  1491.     global lastMatchingLines
  1492.     
  1493.     set reqPat {^[     ]*require[     ]*(¥"[^¥"]+¥"|¥'[^¥']+¥'|[^     ]+)}
  1494.     set pos 0
  1495.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $reqPat $pos} mtch]} {
  1496.          [lindex [posToRowCol [lindex $mtch 0]] 0]] 
  1497.         set name [string [eval getText $mtch]
  1498.         set pos [lindex $mtch 1]
  1499.         incr matches
  1500.     }
  1501. }
  1502.  
  1503. # Open a Perl source file. 
  1504. #
  1505. proc openPerlFile {file {extensions {""}}} {
  1506.     global perlSearchPath
  1507.     # Determine absolute file specification
  1508.     # Ignore $extensions if $file already has an extension
  1509.     if {[string length [file extension $file]] == 0} {
  1510.         set extensions {""}
  1511.     }
  1512.     foreach ext $extensions {
  1513.         set filename [absolutePath $file$ext]
  1514.         if {![catch {openFileQuietly $filename}]} {
  1515.             message $filename
  1516.             return 
  1517.         }
  1518.     }
  1519.     if {[llength $perlSearchPath] == 0} { buildPerlSearchPath }
  1520.     foreach folder $perlSearchPath {
  1521.         foreach ext $extensions {
  1522.             set filename "$folder$file$ext"
  1523.             if {![catch {openFileQuietly $filename}]} {
  1524.                 message $filename
  1525.                 return     
  1526.             }
  1527.         }
  1528.     }
  1529.     beep
  1530.     message "can't find Perl source file ¥"$file¥""
  1531. }
  1532.  
  1533. # Return a list of folders in which to search for Perl library files, 
  1534. # including the lib folder in the Perl application directory and the
  1535. # $perlLib folder (if it exists) .  
  1536. # The current folder is not included in the list.
  1537. #
  1538. # (The $perlLib folder is assigned from the AppPaths submenu.)
  1539. #
  1540. proc buildPerlSearchPath {} {
  1541.     global perlLib perlSearchPath
  1542.     message "building Perl search path..."
  1543.     set folders {}
  1544.     
  1545.     # The local lib folder:
  1546.     if {[info exists perlLib] && [string length $perlLib] > 0} { 
  1547.         set folders [concat $folders [list $perlLib]]
  1548.         # Search subfolders one level deep:
  1549.         set folders [concat $folders [listSubfolders $perlLib 1]]
  1550.     }
  1551.  
  1552.     # Any "*lib*" folders in the MacPerl application folder:
  1553.     set macperlPath [nameFromAppl McPL]
  1554.     set appDir [file dirname $macperlPath]
  1555.     set folders [concat $folders [list $appDir]]
  1556.     # Bug:  'glob' is case sensitive!
  1557.     foreach folder [glob "$appDir:*¥[Ll¥]ib*"] {
  1558.         set folders [concat $folders [list $folder]]
  1559.         # Search subfolders one level deep:
  1560.         set folders [concat $folders [listSubfolders $folder 1]]
  1561.     }
  1562.  
  1563.     # Make sure each folder ends with a colon
  1564.     set perlSearchPath {}
  1565.     foreach folder $folders {
  1566.         set folder "[string trimright $folder {:}]:"
  1567.         set perlSearchPath [concat $perlSearchPath [list $folder]]
  1568.     }
  1569. }
  1570.  
  1571. ###########################################################################
  1572.  
  1573.  
  1574.  
  1575.  
  1576. proc perlHelpProc {menu item} {
  1577.     global HOME
  1578.     switch $item {
  1579.         "MacPerl Mode"                {edit -r "$HOME:Help:MacPerl Help"}
  1580.         "Mac Specifics"                {edit -r "$HOME:Help:MacPerl.Specifics"}
  1581.         "Perl4 Commands"                {edit -r "$HOME:Help:Perl Commands"}
  1582.         "Perl5 Manual"                {
  1583.                 if {[file exists "Development:Docs:PerlDocs:perl.html"]} {
  1584.                     global browserSig
  1585.                     set name [file tail [launchBackAppl $browserSig]]
  1586.                     switchTo $name
  1587.                     sendOpenEvent -n $name "Development:Docs:PerlDocs:perl.html"
  1588.                 } else {
  1589.                     alertnote "Only Pete can do that!"
  1590.                 }
  1591.             }
  1592.     }
  1593. }
  1594.  
  1595. proc perlPalette {} {
  1596.     global perlMenu
  1597.     float -m $perlMenu -n Perl -M 2
  1598. }
  1599.  
  1600. bind '¥r' tclCarriageReturn Perl
  1601. bind '¥}' <s> electricRight Perl
  1602. bind '¥{' <s> electricLeft Perl
  1603. bind '¥;' electricSemi Perl
  1604. bind '¥t' <z> doATab Perl
  1605.